using System;
using System.IO;
using System.Text;

namespace MySoftLab.DapFlash.Models
{
    public class IntelHexWriter
    {
        private const int DATA_RECORD = 0x00;
        private const int END_OF_FILE_RECORD = 0x01;
        private const int EXTENDED_LINEAR_ADDRESS_RECORD = 0x04;
        private const int BYTES_PER_LINE = 16; // 每行的字节数

        /// <summary>
        /// 将二进制数据保存为Intel HEX格式文件
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="data">二进制数据</param>
        /// <param name="filePath">保存路径</param>
        public void SaveToHexFile(uint startAddress, byte[] data, string filePath)
        {
            if (data == null || data.Length == 0)
                throw new ArgumentException("数据不能为空");

            using var writer = new StreamWriter(filePath, false, Encoding.ASCII);
            
            uint currentAddress = startAddress;
            uint lastExtendedAddress = 0xFFFFFFFF; // 初始设为无效值
            
            for (int offset = 0; offset < data.Length; offset += BYTES_PER_LINE)
            {
                // 计算当前行需要处理的字节数
                int lineLength = Math.Min(BYTES_PER_LINE, data.Length - offset);
                
                // 检查是否需要写入扩展线性地址记录
                uint currentExtendedAddress = (currentAddress + (uint)offset) >> 16;
                if (currentExtendedAddress != lastExtendedAddress)
                {
                    lastExtendedAddress = currentExtendedAddress;
                    WriteExtendedLinearAddressRecord(writer, currentExtendedAddress);
                }
                
                // 写入数据记录
                WriteDataRecord(writer, (uint)((currentAddress + offset) & 0xFFFF), data, offset, lineLength);
            }
            
            // 写入文件结束记录
            WriteEndOfFileRecord(writer);
        }
        
        /// <summary>
        /// 写入扩展线性地址记录
        /// </summary>
        private void WriteExtendedLinearAddressRecord(StreamWriter writer, uint extendedAddress)
        {
            byte[] addressBytes = new byte[2];
            addressBytes[0] = (byte)((extendedAddress >> 8) & 0xFF);
            addressBytes[1] = (byte)(extendedAddress & 0xFF);
            
            byte checksum = CalculateChecksum(2, 0, EXTENDED_LINEAR_ADDRESS_RECORD, addressBytes, 0, 2);
            writer.WriteLine($":02000004{addressBytes[0]:X2}{addressBytes[1]:X2}{checksum:X2}");
        }
        
        /// <summary>
        /// 写入数据记录
        /// </summary>
        private void WriteDataRecord(StreamWriter writer, uint address, byte[] data, int offset, int length)
        {
            byte checksum = CalculateChecksum((byte)length, (ushort)address, DATA_RECORD, data, offset, length);
            
            StringBuilder sb = new StringBuilder();
            sb.Append($":{length:X2}{address:X4}{DATA_RECORD:X2}");
            
            for (int i = 0; i < length; i++)
            {
                sb.Append($"{data[offset + i]:X2}");
            }
            
            sb.Append($"{checksum:X2}");
            writer.WriteLine(sb.ToString());
        }
        
        /// <summary>
        /// 写入文件结束记录
        /// </summary>
        private void WriteEndOfFileRecord(StreamWriter writer)
        {
            // 文件结束记录格式: :00000001FF
            writer.WriteLine(":00000001FF");
        }
        
        /// <summary>
        /// 计算校验和
        /// </summary>
        private byte CalculateChecksum(byte byteCount, ushort address, byte recordType, byte[] data, int offset, int length)
        {
            int sum = byteCount;
            sum += (address >> 8) & 0xFF;
            sum += address & 0xFF;
            sum += recordType;
            
            for (int i = 0; i < length; i++)
            {
                sum += data[offset + i];
            }
            
            return (byte)(0x100 - (sum & 0xFF));
        }
    }
} 